"""
pandas 含有使数据清洗和分析工作变得更快更简单的数据结构和操作工具
如数值计算工具NumPy和SciPy，分析库statsmodels和scikit-learn，和数据可视化库matplotlib。pandas是基于NumPy数组构建的，特别是基于数组的函数和不使用for循环的数据处理。

虽然pandas采用了大量的NumPy编码风格，但二者最大的不同是pandas是专门为处理表格和混杂数据设计的。而NumPy更适合处理统一的数值数组数据。
pandas的两个主要数据结构 Series 和 DataFrame
Series 是一种类似于一维数组对象 它由一组数据以及一组与之相关的数据标签即索引  仅由一组数据即可产生最简单的Series
obj = pd.Series([4,7,-5,3])
由两部分组成
数据:存储实际的数据值
索引:与数据意义对应的标签 默认情况下整数索引 从0开始

0    4
1    7
2   -5
3    3
dtype: int64
左侧:表示索引(默认为[0,1,2,3])
右侧：表示数据值 [4, 7, -5, 3]。
dtype：表示数据类型，在这里是 int64（64 位整数）。
pd.Series 中是基础数据结构之一,适用于一维数据的存储和操作

可以通过Series的values和index属性获取其数组表示形式和索引对象
obj = pd.Series([4,7,-5,3])
print(obj.values)
print(obj.index)

# 创建的Series带有一个可以对各个数据点进行标记的索引
obj2 = pd.Series([4,7,-5,3],index=['d','b','a','c'])
print(obj2.index)
print(obj2)
print(obj2['a'])  # 通过索引的方式选取Series中的元素 获取索引为a的元素
obj2['d'] = 6
print(obj2[['c','a','d']])  # ['c','a','d'] 是索引列表 即使它包含的是字符串而不是整数

# 使用NumPy函数或类似NumPy的运算 都会保留索引值的链接
print(obj2[obj2 > 0])  # obj2 > 0 返回一个布尔数组
print(obj2 * 2) # obj2 * 2 生成一个Series
print(np.exp(obj2)) # np.exp(obj2) 返回一个Series np.exp用于计算以自然常数e为底的指数函数 e^x
print('b' in obj2)  # 判断索引是否存在 将Series 看成一个定长有序字典 因为索引值到数据值的一个映射


# 直接通过这个字典来创建Series
sdata = {'Ohio': 35000, 'Texas': 71000, 'Oregon': 16000, 'Utah': 5000}
obj3 = pd.Series(sdata)
print(obj3)

# 如果只传入一个字典 则结果Series的索引就是原字典的键 有序排列 可以传入排好序的字典的键以改变顺序
states = ['California', 'Ohio', 'Oregon', 'Texas']
obj4 = pd.Series(sdata, index=states)
print(obj4)
# sdata中跟states索引相匹配的那3个值会被找出来并放到相应的位置上，但由于”California”所对应的sdata值找不到，
# 所以其结果就为NaN（即“非数字”（not a number），在pandas中，它用于表示缺失或NA值）。因为‘Utah’不在states中，它被从结果中除去。

# 使用 缺失missing或NA值来填充缺失值 pandas的isnull和notnull函数可用于检测缺失值
print(pd.isnull(obj4)) # isnull返回一个布尔数组 用于就按测数据中的缺失值 NaN或None 如果存在缺失值则返回True 如果不存在缺失值则返回False
print(pd.notnull(obj4)) # notnull返回一个布尔数组 如果不是NaN 或 None 返回 True 否则返回 False
# Series最重要的一个功能是会根据运算的索引标签自动对齐数据 Series对象本身及其索引都有一个name属性
obj4.name = 'population' #Pandas Series 对象 obj4 设置了一个名称（name 属性）名称可以用来描述该 Series 的数据内容，通常在数据分析和可视化中起到标注作用。
# 设置后，obj4 的名称会显示在输出结果中，特别是在与 DataFrame 结合使用或生成图表时
obj4.index.name = 'state'
# 这行代码为 obj4 的索引（index）设置了一个名称（name 属性）。
# 索引名称可以用来描述索引的含义，类似于数据库中的列名。
# 设置后，obj4 的索引名称会在输出结果中显示，尤其是在多级索引或 DataFrame 中更常用。


# 假设 obj4 的初始内容如下
# sdata = {'Ohio': 35000, 'Texas': 71000, 'Oregon': 16000, 'Utah': 5000}
# states = ['California', 'Ohio', 'Oregon', 'Texas']
# obj4 = pd.Series(sdata, index=states)

# obj4.name = 'population'
# obj4.index.name = 'state'
# print(obj4)

# state
# California      NaN
# Ohio        35000.0
# Oregon      16000.0
# Texas       71000.0
# Name: population, dtype: float64

obj.index = ['Bob', 'Steve', 'Jeff', 'Ryan'] 索引可以通过赋值的方式就地修改

DataFrame 是一个表格型的数据结构 它含有一组有序的列,每列可以是不同的值类型
DataFrame 即有行索引也有列索引 Series组成的字典共用同一个索引
DataFrame 中的数据是以一个或多个二维块存放的

# 创建DataFrame 的方式是直接传入一个由等长列表或NumPy数组组成的字典
data = {'state': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada', 'Nevada'],
        'year': [2000, 2001, 2002, 2001, 2002, 2003],
        'pop': [1.5, 1.7, 3.6, 2.4, 2.9, 3.2]}
frame = pd.DataFrame(data)
print(frame)  #会自动加上索引 ,且全部列会被有序排列
frame.head() # 会选取前5行
frame1 = pd.DataFrame(data, columns=['year', 'state', 'pop']) #指定了列序列 DataFrame 的列的顺序会按照列表中列的顺序排列
print(frame1)

frame2 = pd.DataFrame(data, columns=['year', 'state', 'pop', 'debt'],
                      index=['one', 'two', 'three', 'four','five', 'six'])
print(frame2)  # 如果传入列在数据中找不到,就会在结果中产生缺失值（NaN）
print(frame2.columns) # 获取列索引

# 通过类似字典标记的方式或属性的方式 可以将DataFrame的列获取为一个Series
print(frame2['state'])
print(frame2.year)
# 注意 返回的是Series拥有原DataFrame相同的索引 且其name属性也已经被相应地设置好了
# 行可以通过位置或名称的方式进行获取 比如用 loc属性
print(frame2.loc['three']) # 通过行索引获取行
# 列可以通过赋值的方式进行修改 比如 可以给空的debt 列赋上一个标量值或一组值
frame2['debt'] = 16.5
print(frame2)

frame2['debt'] = np.arange(6.) # 也可以给列赋值 赋予一个数组
print(frame2)

# 将列表或数组赋值给某个列,其长度必须跟DataFrame的长度相匹配 如果赋值的是一个Series,则必须跟DataFrame的索引匹配,所有的空位将会被填充为缺失值
val = pd.Series([-1.2, -1.5, -1.7], index=['two', 'four', 'five'])
frame2['debt'] = val
print(frame2)

# 先添加一个新的布尔值的列,state是否为 'Ohio'
frame2['eastern_state'] = frame2.state == 'Ohio' # 创建一个布尔值列,state列的值为'Ohio'则为True,否则为False
# 使用del方法可以用来删除列
del frame2['eastern']
print(frame2.columns) # 删除后 列索引会更新

# 嵌套字典
pop = {'Nevada': {2001: 2.4, 2002: 2.9},'Ohio': {2000: 1.5, 2001: 1.7, 2002: 3.6}}
# 如果嵌套字典传给DataFrame,pandas就会被解释为:外层字典的键作为列,内层键则作为行索引
frame3 = pd.DataFrame(pop)
# 类似NumPy数组的方法 对DataFrame进行转置 交换行和列
print(frame3.T)
# 内层字典的键会被合并,排序以及形成最终的索引
print(pd.DataFrame(pop, index=[2001, 2002, 2003]))
# 由Series组成的字典也差不多
pdata = {'Ohio': frame3['Ohio'][:-1],'Nevada': frame3['Nevada'][:2]}
frame4 = pd.DataFrame(pdata)

frame3.index.name = 'year'; frame3.columns.name = 'state'
print(frame3)

Index的方法和属性
append
连接另一个Index对象，产生一个新的Index
difference
计算差集，并得到一个Index
intersection
计算交集
union
计算并集
isin
计算一个指示各值是否都包含在参数集合中的布尔型数组
delete
删除索引i处的元素，并得到新的ndex
drop
删除传入的值，并得到新的Index
insert
将元素插入到索引i处，并得到新的Index
is monotonic
当各元素均大于等于前一个元素时，返回True
is unique
当Index?没有重复值时，返回True
unique
计算Index中唯一值的数组

# 索引对象赋值管理轴标签和其他元数据 构建Series或DataFrame时,所用的任何数组或其他序列的标签都会被转换成一个Index对象
obj = pd.Series(range(3), index=['a', 'b', 'c'])
index = obj.index
print(index)
print(index[1:])
# index[1]='d' # Index对象是不可变的,因此用户不能对其进行修改
# 不可变可以使index对象在多个数据结构之间安全共享
labels = pd.Index(np.arange(3))
print(labels)
obj2 = pd.Series([1.5, -2.5, 0], index=labels)
print(obj2)
print(obj2.index is labels)

基础功能
重新索引 pandas最重要方式是reindex 作用是创建一个新对象 它的数据符合新的索引
obj = pd.Series([4.5, 7.2, -5.3, 3.6], index=['d', 'b', 'a', 'c'])
print(obj)
# 使用Series的reindex将会根据新索引进行重排 如果某个索引值当前不存在就引入缺失值
obj2 = obj.reindex(['a', 'b', 'c', 'd', 'e'])
print(obj2)

# 对于时间序列这样有序数据 重新索引时需要做一些插值处理 使用method选项  使用ffill可以实现前向值填充
obj3 = pd.Series(['blue', 'purple', 'yellow'], index=[0, 2, 4])
# 创建一个 Pandas Series 对象 obj3。
# 数据为 ['blue', 'purple', 'yellow']，索引为 [0, 2, 4]。
print(obj3)

obj4 = obj3.reindex(np.arange(6), method='ffill')
# 调用 reindex 方法对 obj3 进行重新索引。
# 参数说明：
# np.arange(6)：生成新的索引 [0, 1, 2, 3, 4, 5]。
# method='ffill'：表示使用前向填充（forward fill）方法。如果新索引中某些值在原 Series 中不存在，则用前面最近的值进行填充。
# 新索引为 [0, 1, 2, 3, 4, 5]。
# 使用前向填充（ffill）：
# 索引 0 存在于原 Series 中，值为 'blue'。
# 索引 1 不存在于原 Series 中，前向填充为 'blue'。
# 索引 2 存在于原 Series 中，值为 'purple'。
# 索引 3 不存在于原 Series 中，前向填充为 'purple'。
# 索引 4 存在于原 Series 中，值为 'yellow'。
# 索引 5 不存在于原 Series 中，前向填充为 'yellow'。
print(obj4)

# 借助 DataFrame 的 reindex 方法，可以修改行索引 和列 只传递一个序列 只重新索引结果的行
frame = pd.DataFrame(np.arange(9).reshape((3, 3)), index['a', 'c', 'd'], columns=['Ohio', 'Texas', 'California'])
# np.arange(9)：
# 使用 NumPy 的 arange 函数生成一个从 0 到 8 的数组 [0, 1, 2, 3, 4, 5, 6, 7, 8]。
# reshape((3, 3))：
# 将生成的数组重新调整为形状为 (3, 3) 的二维数组：
#     [[0, 1, 2],
#      [3, 4, 5],
#      [6, 7, 8]]
# pd.DataFrame(...)：
# 创建一个 Pandas DataFrame 对象。
# 参数说明：
# 数据：使用上述 (3, 3) 的二维数组作为数据。
# 行索引：index=['a', 'c', 'd']，表示行标签为 ['a', 'c', 'd']。
# 列名：columns=['Ohio', 'Texas', 'California']，表示列名为 ['Ohio', 'Texas', 'California']。      Ohio  Texas  California
#   a      0      1           2
#   c      3      4           5
#   d      6      7           8
print(frame)
frame2 = frame.reindex(['a', 'b', 'c', 'd']) # 重新索引行
#       Ohio  Texas  California
#   a    0.0    1.0         2.0
#   b    NaN    NaN         NaN
#   c    3.0    4.0         5.0
#   d    6.0    7.0         8.0
print(frame2)

# 对列可以用columns关键字 重新索引
states = ['Texas', 'Utah', 'California']
frame.reindex(columns=states)
#      Ohio  Texas  California
#   a    NaN    1.0        NaN
#   b    NaN    NaN        NaN
#   c    NaN    4.0        5.0
#   d    NaN    7.0        8.0

reindex 函数的参数
index
用作索引的新序列。既可以是Index实例，也可以是其他序列型的Python数
据结构。Index会被完全使用，就像没有任何复制一样
method
插值（填充）方式
fill_value
在重新索引的过程中，需要引入缺失值时使用的替代值
limit
前向或后向填充时的最大填充量
tolerance
向前后向后填充时，填充不准确匹配项的最大间距（绝对值距离）
level
在Multilndex的指定级别上匹配简单索引，否则选取其子集
copy
默认为True,无论如何都复制；如果为False,则新旧相等就不复制

# 丢弃指定轴上的项 丢弃某条轴上的一个或多个项 只要有一个索引数组或列表即可
# drop方法返回的是一个在指定轴上删除了指定值的新对象
obj = pd.Series(np.arange(5), index=['a', 'b', 'c', 'd', 'e'])
print(obj)
# a    0
# b    1
# c    2
# d    3
# e    4
# dtype: int32
new_obj = obj.drop('c') # 丢弃c 丢弃索引为c的项
print(new_obj)
# a    0
# b    1
# d    3
# e    4
# dtype: int32
new_obj1 = obj.drop(['d', 'c']) # 丢弃d和c 丢弃索引为d和c的项
print(new_obj1)
# a    0
# b    1
# e    4
# dtype: int32

# 对于DataFrame，可以删除任意轴上的索引值
data = pd.DataFrame(np.arange(16).reshape((4, 4)),index=['Ohio', 'Colorado', 'Utah', 'New York'],columns=['one', 'two', 'three', 'four'])
print(data)
#           one  two  three  four
# Ohio        0    1      2     3
# Colorado    4    5      6     7
# Utah        8    9     10    11
# New York   12   13     14    15

# 用标签序列调用drop 会从行标签 axis0 删除值
print(data.drop(['Colorado', 'Ohio']))
#           one  two  three  four
# Utah        8    9     10    11
# New York   12   13     14    15

# 通过传递 axis=1 或 axis='columns'，可以删除列标签
print(data.drop('two', axis=1))
#           one  three  four
# Ohio        0      2     3
# Colorado    4      6     7
# Utah        8     10    11
# New York   12     14    15
print(data.drop(['two', 'four'], axis='columns'))
#           one  three
# Ohio        0      2
# Colorado    4      6
# Utah        8     10
# New York   12     14
# drop会修改Series或DataFrame的大小或形状，可以就地修改对象不会返回新的对象
obj = pd.Series(np.arange(5.), index=['a', 'b', 'c', 'd', 'e'])
obj.drop('c', inplace=True) # inplace=True 会销毁所有被删除的数据
# 调用 drop 方法删除指定的索引项。
# 参数说明：
# 'c'：表示要删除的索引标签。
# inplace=True：表示直接在原对象上进行修改，而不是返回一个新的对象。
# 删除过程：
# 索引 'c' 对应的数据值 2.0 将被移除。
# 修改后的 obj 不再包含索引 'c'。

# 索引 选取和过滤 Series索引 的工作方式类似Numpy数组索引 只不过Series的索引值不只是整数
obj = pd.Series(np.arange(4.), index=['a', 'b', 'c', 'd'])
print(obj)
# a    0.0
# b    1.0
# c    2.0
# d    3.0
# dtype: float64

print(obj['b'])  # 获取索引为b的值
print(obj[1])  # 获取索引为1的值
print(obj[2:4])  # 获取索引为2和3的值
print(obj[['b', 'a', 'd']])  # 获取索引为b,a,d的值
print(obj[[1, 3]])  # 获取索引为1和3的值
print(obj[obj < 2])  # 获取索引为a,b的值
print(obj['b':'c'])  # 获取索引为b到c的值 与普通的python切片不同 其末端是包含的
# 使用切片对Series进行赋值
obj['b':'c'] = 5
print(obj)
# a    0.0
# b    5.0
# c    5.0
# d    3.0
# dtype: float64
# 用一个值或序列对DataFrame进行索引 其实就是获取一个或多个列
data = pd.DataFrame(np.arange(16).reshape((4, 4)),
                    index=['Ohio', 'Colorado', 'Utah', 'New York'],
                    columns=['one', 'two', 'three', 'four'])
data['two']  # 获取列名为two的列
data[['three', 'one']]  # 获取列名为three和one的列
data[:2]  # 获取索引为0到1的行
data[data['three'] > 5]  # 获取索引为three列大于5的行
data < 5  # 通过布尔型DataFrame 进行索引 获取索引为three列大于5的行
data[data < 5] = 0 # 通过布尔型DataFrame 进行赋值

# 用loc和iloc进行索引 轴标签 loc 或整数索引 iloc 从DataFrame选择行和列的子集
data.loc['Colorado', ['two', 'three']]
# 使用 .loc 方法按标签选取数据。
# 参数说明：
# 'Colorado'：表示选取行索引为 'Colorado' 的行。
# ['two', 'three']：表示选取列名为 'two' 和 'three' 的列。
data.iloc[2, [3, 0, 1]]
# 使用 .iloc 方法按位置选取数据。
# 参数说明：
# 2：表示选取第 2 行（从 0 开始计数，对应行索引 'Utah'）。
# [3, 0, 1]：表示选取第 3、0 和 1 列（从 0 开始计数，对应列名 'four'、'one' 和 'two'）。
data.iloc[2]
# 使用 .iloc 方法按位置选取整行数据。
# 参数说明：
# 2：表示选取第 2 行（从 0 开始计数，对应行索引 'Utah'）。
data.iloc[[1,2],[3,0,1]]
# 使用 .iloc 方法按位置选取多行和多列数据。
# 参数说明：
# [1, 2]：表示选取第 1 和 2 行（从 0 开始计数，对应行索引 'Colorado' 和 'Utah'）。
# [3, 0, 1]：表示选取第 3、0 和 1 列（从 0 开始计数，对应列名 'four'、'one' 和 'two'）。

data.loc[:'Utah','two']
# 使用 .loc 方法按标签选取数据。
# 参数说明：
# :'Utah'：表示选取行索引为 'Ohio' 到 'Utah' 的行（包括 'Utah'）。
# 'two'：表示选取列名为 'two' 的列。
data.iloc[:, :3][data.three > 5]
# 使用 .loc 方法按标签选取数据。
# 参数说明：
# :：表示选取所有行。
# :3：表示选取

# 整数索引
# ser = Series(np.arange(3.))
ser = Series(np.arange(3.),index=[0,1,-1]) # 如果需要使用ser[-1] 可以重新设置索引 使其包含-1
# print(ser.to_numpy()[-1]) #也可以将series转换成Numpy数组
# np.arange(3.)：生成一个从 0 到 2 的浮点数数组 [0.0, 1.0, 2.0]。
# Series(np.arange(3.))：将数组 [0.0, 1.0, 2.0] 转换为 Pandas 的 Series 对象，索引默认为 [0, 1, 2]。
print(ser)
# print(ser[-1])
# 在 Pandas 中，Series 的索引可以是任意类型的值（如字符串、整数等）。当使用负数索引（如 -1）时，Pandas 默认会检查是否存在索引值为 -1 的元素，而不是像 NumPy 或 Python 列表那样支持基于位置的负数索引。
# 如果 Series 的索引中没有 -1，则会抛出 KeyError 错误。
print(ser.iloc[-1])
# 使用 .iloc 方法进行整数索引。访问最后一个元素。
# 参数说明：
# -1：表示选取第 -1 个元素（从 0 开始计数，对应索引值为 -1）。

# 算术运算和数据对齐 pandas最重要的功能是可以对不同索引的对象进行算术运算 将对象相加时,如果存在不同的索引对 则结果的索引就是该索引对的并集
s1 = pd.Series([7.3, -2.5, 3.4, 1.5], index=['a', 'c', 'd', 'e'])
s2 = pd.Series([-2.1, 3.6, -1.5, 4, 3.1],index=['a', 'c', 'e', 'f', 'g'])
print(s1)
print(s2)
# 不同索引的进行相加 自动的数据对齐操作在不重叠的索引处引入了NA值 缺失值会在算术运算过程中传播
print(s1 + s2)

# DataFrame 对齐操作会同时发生在行和列上
df1 = pd.DataFrame(np.arange(9.).reshape((3, 3)), columns=list('bcd'), index=['Ohio', 'Texas', 'Colorado'])
df2 = pd.DataFrame(np.arange(12.).reshape((4, 3)), columns=list('bde'),index=['Utah', 'Ohio', 'Texas', 'Oregon'])
#  np.arange(12.)
# 使用 NumPy 的 arange 函数生成一个从 0.0 到 11.0 的浮点数数组：
# reshape((4, 3))
# 将生成的数组重新调整为形状为 (4, 3) 的二维数组：
# pd.DataFrame(...)
# 创建一个 Pandas DataFrame 对象。
# 参数说明：
# 数据：使用上述 (4, 3) 的二维数组作为数据。
# 列名：columns=list('bde')，表示列名为 ['b', 'd', 'e']。
# 行索引：index=['Utah', 'Ohio', 'Texas', 'Oregon']，表示行标签为 ['Utah', 'Ohio', 'Texas', 'Oregon']。
print(df1)
print(df2)

# 如果两个DataFrame对象长度不一致时,进行相加 其索引和列为原来两个DataFrame的并集
print(df1 + df2)
# 因为c和e列不在两个DataFrame对象只能,在结果中以缺省值呈现 行也是同样
# 如果DataFrame 对象相加 没有共用的列或行标签 结果都是空

df1 = pd.DataFrame({'A':[1,2]})
# 创建一个 Pandas DataFrame 对象 df1。
# 参数说明：
# {'A': [1, 2]}：表示列名为 'A'，数据为 [1, 2]。
# 默认情况下，行索引为 [0, 1]。
#     A
#   0  1
#   1  2
df2 = pd.DataFrame({'B':[3,4]})
print(df1)
print(df2)
print(df1 - df2)

# 在不同索引的对象进行算术运算时,希望当一个对象中某个轴标签在另一个对象中找不到时填充一个特殊值比如0
df1 = pd.DataFrame(np.arange(12.).reshape((3, 4)),columns=list('abcd'))
# 创建一个 Pandas DataFrame 对象 df1。
# 参数说明：
# np.arange(12.)：生成一个从 0.0 到 11.0 的浮点数数组 [0.0, 1.0, 2.0, ..., 11.0]。
# .reshape((3, 4))：将数组重新调整为形状为 (3, 4) 的二维数组：
# columns=list('abcd')：指定列名为 ['a', 'b', 'c', 'd']。
# 默认情况下，行索引为 [0, 1, 2]。
#        a     b     c     d
#    0  0.0   1.0   2.0   3.0
#    1  4.0   5.0   6.0   7.0
#    2  8.0   9.0  10.0  11.0
df2 = pd.DataFrame(np.arange(20.).reshape((4, 5)),columns=list('abcde'))
df2.loc[1,'b'] = np.nan
# 修改 df2 中第 1 行、列名为 'b' 的值为 np.nan（表示缺失值）。
# 运算过程：
# df2.loc[1, 'b']：定位到 df2 的第 1 行、列名为 'b' 的位置。
# 将该位置的值设置为 np.nan。
#        a     b     c     d     e
#    0  0.0   1.0   2.0   3.0   4.0
#    1  5.0   NaN   7.0   8.0   9.0
#    2 10.0  11.0  12.0  13.0  14.0
#    3 15.0  16.0  17.0  18.0  19.0
print(df1)
print(df2)
# 将它们相加时 没有重叠的位置就会产生NA值
print(df1 + df2)
print(df1.add(df2, fill_value=0))
# 这是 Pandas 中 DataFrame 的算术运算方法之一，用于执行加法操作。
# 参数说明：
# df2：表示与 df1 进行加法运算的另一个 DataFrame。
# fill_value=0：当两个 DataFrame 的索引或列不完全匹配时，缺失值会被填充为指定的 fill_value（这里是 0），然后再进行计算。
# 在 Pandas 中，DataFrame 的算术运算会自动对齐索引和列。如果某个位置在其中一个 DataFrame 中存在，但在另一个中不存在，则默认情况下会生成缺失值（NaN）。
# 使用 fill_value 参数可以指定如何处理这些缺失值。例如，将缺失值替换为 0，从而避免生成 NaN。
# df1
#      a    b    c    d
# 0  0.0  1.0  2.0  3.0
# 1  4.0  5.0  6.0  7.0
# 2  8.0  9.0 10.0 11.0
# df2
#      a    b    c    d    e
# 0  0.0  1.0  2.0  3.0  4.0
# 1  5.0  NaN  7.0  8.0  9.0
# 2 10.0 11.0 12.0 13.0 14.0
# 3 15.0 16.0 17.0 18.0 19.0
# 执行 df1.add(df2, fill_value=0) 的步骤如下：
# 对齐索引和列：
# df1 的行索引为 [0, 1, 2]，df2 的行索引为 [0, 1, 2, 3]，因此结果的行索引为两者的并集 [0, 1, 2, 3]。
# df1 的列为 ['a', 'b', 'c', 'd']，df2 的列为 ['a', 'b', 'c', 'd', 'e']，因此结果的列为两者的并集 ['a', 'b', 'c', 'd', 'e']。
# 填充缺失值：
# 对于 df1 或 df2 中缺失的部分，使用 fill_value=0 填充。
# 例如：
# df1 没有索引 3，因此在计算时，df1 的第 3 行会被填充为 0。
# df2 没有列 e，因此在计算时，df1 的列 e 会被填充为 0。
# 逐元素相加：
# 按照对齐后的索引和列，逐元素相加。

print(1/df1)
# 这是 Pandas 中的逐元素算术运算。
# 1 / df1 表示将标量值 1 与 DataFrame df1 的每个元素进行除法运算。
# 如果 df1 中的某个元素为 0，则结果会生成 inf（正无穷）或 -inf（负无穷），因为数学上除以零是未定义的。
# 如果 df1 中有缺失值（NaN），则结果中对应位置也会是 NaN。
#          a         b         c         d
# 0       inf  1.000000  0.500000  0.333333
# 1  0.250000  0.200000  0.166667  0.142857
# 2  0.125000  0.111111  0.100000  0.090909
# 第 0 行的 a 列为 0.0，因此 1 / 0.0 结果为 inf。
# 其他位置的结果是 1 / df1 的对应值。
# 执行 df1.rdiv(1) 的结果：
# df1.rdiv(1) 的结果与 1 / df1 完全相同：
print(df1.rdiv(1))
# rdiv 是 Pandas 提供的一种反向操作方法（reverse operation）。
# df1.rdiv(1) 等价于 1 / df1，即表示将标量值 1 作为被除数，df1 的每个元素作为除数进行除法运算。
# 使用 rdiv 方法的好处在于，它可以更清晰地表达反向操作的意图，尤其是在处理复杂表达式时。
# add,radd
# 用于加法(+)的方法
# sub,rsub
# 用于减法(-)的方法
# div,rdiv
# 用于除法()的方法
# floordiv,rfloordiv
# 用于底除()的方法
# mul,rmul
# 用于乘法(*)的方法
# pow,rpow
# 用于指数(*)的方法

"""
from operator import index

import numpy as np
import pandas as pd
from numpy.ma.core import reshape
from pandas import Series, DataFrame


# 计算一个二维数组与其某行之间的差
arr = np.arange(12.).reshape((3, 4))
# 这行代码创建了一个二维数组 arr，其内容是从 0 到 11 的浮点数，并将其形状调整为 (3, 4)。
# 具体步骤：
# np.arange(12.)：
# 使用 NumPy 的 arange 函数生成一个从 0.0 到 11.0 的浮点数数组 [0.0, 1.0, 2.0, ..., 11.0]。
# .reshape((3, 4))：
# 将一维数组重新调整为形状为 (3, 4) 的二维数组：
#       [[ 0.  1.  2.  3.]
#        [ 4.  5.  6.  7.]
#        [ 8.  9. 10. 11.]]
print(arr)
print(arr[0])
# [0. 1. 2. 3.]
print(arr - arr[0])
# 这行代码计算了数组 arr 中每一行与第 0 行的差值。这利用了 NumPy 的 广播机制。
# 广播机制：
# 在 NumPy 中，当对一个二维数组和一个一维数组进行运算时，NumPy 会自动将一维数组扩展到与二维数组兼容的形状。
# 具体来说，arr[0] 是一个长度为 4 的一维数组 [0. 1. 2. 3.]，它会被广播到与 arr 的每一行相匹配的形状 (3, 4)。
# 然后逐元素执行减法操作。
# 计算过程：
# 第 0 行：[0. 1. 2. 3.] - [0. 1. 2. 3.] = [0. 0. 0. 0.]
# 第 1 行：[4. 5. 6. 7.] - [0. 1. 2. 3.] = [4. 4. 4. 4.]
# 第 2 行：[8. 9. 10. 11.] - [0. 1. 2. 3.] = [8. 8. 8. 8.]
# 当从arr减去arr[0]时 每行都会执行这个操作 这就叫做广播

# 根据条件对数据集排序sorting 要对行或列索引进行排序 按字典顺序 sort_index方法 将返回一个已排序的新对象
obj = pd.Series(range(4), index=['d', 'a', 'b', 'c'])
print(obj.sort_index()) # 按字典顺序排序
# 输出结果：
# a    0
# b    1
# c    2
# d    3
# dtype: int64
frame = pd.DataFrame(np.arange(8).reshape((2, 4)),index=['three', 'one'],columns=['d', 'a', 'b', 'c'])
# 创建一个 Pandas DataFrame 对象 frame。
# 具体步骤：
# np.arange(8)：
# 使用 NumPy 的 arange 函数生成一个从 0 到 7 的整数数组 [0, 1, 2, ..., 7]。
# .reshape((2, 4))：
# 将一维数组重新调整为形状为 (2, 4) 的二维数组：
print(frame.sort_index())
# 调用 sort_index() 方法对 frame 的行索引进行排序。
# 默认参数：
# axis=0：表示对行索引进行排序。
# ascending=True：表示按升序排序。
# 排序过程：
# 原始行索引为 ['three', 'one']，按字典顺序排序后变为 ['one', 'three']。
#         d  a  b  c
#   one    4  5  6  7
#   three  0  1  2  3
print(frame.sort_index(axis=1))
# 调用 sort_index(axis=1) 方法对 frame 的列索引进行排序。
# 参数说明：
# axis=1：表示对列索引进行排序。
# ascending=True：表示按升序排序。
# 排序过程：
# 原始列索引为 ['d', 'a', 'b', 'c']，按字典顺序排序后变为 ['a', 'b', 'c', 'd']。
#         a  b  c  d
#   three  1  2  3  0
#   one    5  6  7  4
# 若要按值对Series进行排序 可使用sort_values()方法
obj = pd.Series([4, 7, -3, 2])
print(obj.sort_values())
# 在排序时,任何缺失值默认都会被放到Series的末尾。
obj = pd.Series([4, np.nan, 7, np.nan, -3, 2])
print(obj.sort_values())
# 4   -3.0
# 5    2.0
# 0    4.0
# 2    7.0
# 1    NaN
# 3    NaN
# dtype: float64

if __name__ == '__main__':
    pass
